import random
datalen = 1000
data_bytes = random.randbytes(datalen)

# generate input 

# format
# { sub , idx }

split_points = [0]
current = 0
n = len(data_bytes)
while current < n:
    max_step = n - current
    step = random.randint(1, max_step)
    current += step
    if current < n:
        split_points.append(current)
split_points.append(n)
mandatory = [
    {
        "idx" : split_points[i-1],
        "sub" : data_bytes[split_points[i-1]:split_points[i]]
    } 
    for i in range(1, len(split_points))
]

data_bytes_str = '' + (
            ''.join(
                [ 
                    ("\n" if i % 16 ==0 else "") +
                    format(data_bytes[i],'02x') + ' ' 
                    for i in range(0, len(data_bytes)) 
                ]
            )
        )

print(data_bytes_str)

for m in mandatory:
    print(
        'idx:' + str(m['idx']) +
        '\n' +
        'bytedump:' + '' + (
            ''.join(
                [ 
                    ("\n\t" if i % 16 ==0 else "") +
                    format(m['sub'][i],'02x') + ' ' 
                    for i in range(0, len(m['sub'])) 
                ]
            )
        )
    )
print()

subbytes_list = []

for sub in mandatory :
    sublist_subbytes = []
    sublist_subbytes.append(sub)
    n = len(data_bytes)
    for _ in range(20):
        if n == 0:
            break
        start = random.randint(0, n-1)
        end = random.randint(start + 1, n)
        sublist_subbytes.append(
            {
                "idx" : start,
                "sub" : data_bytes[start:end]
            }
        )
    random.shuffle(sublist_subbytes)
    subbytes_list.extend(sublist_subbytes)


# subbytes_list.extend(mandatory)

for m in subbytes_list:
    print(
        'idx:' + str(m['idx']) +
        '\n' +
        'bytedump:' + '' + (
            ''.join(
                [ 
                    ("\n\t" if i % 16 ==0 else "") +
                    format(m['sub'][i],'02x') + ' ' 
                    for i in range(0, len(m['sub'])) 
                ]
            )
        )
    )

# format them
#

print()

cpp_file_out = open('/home/lsr/project/Computer_Network/Assignment/apps/lab1_test.hh','w')

test_statement_list = []
test_statement_list.append(
    f'\tauto test = std::make_unique<ReassemblerTestHarness>({datalen});'
)

for sub in subbytes_list:
    idx     = sub['idx']
    bytestr = ''.join([ '\\x'+format(i,'02x') for i in sub['sub'] ])
    bytelen = len(sub['sub'])
    
    testcase_format = f"SubmitSegment{{std::string(\"{bytestr}\",{bytelen}),{idx}}}"
    testcase_statement = f"\ttest->execute({testcase_format});"
    
    test_statement_list.append(testcase_statement)

test_end = [
        f"\ttest->execute(BytesAssembled({datalen}));",
        f"\ttest->execute(BytesAvailable(std::string(\"{''.join([ '\\x' + format(i,'02x') for i in data_bytes])}\" , {datalen}) ) );",
        "\ttest->execute(NotAtEof{});"
]

test_statement_list.extend(
    test_end
)

function_defination = \
f'''
#include "fsm_stream_reassembler_harness.hh"

#include <string>
#include <iostream>
#include <memory>
using namespace std;

// hex dump of this generated cases :
{ 
    ''.join (
        [
            ("\n//" if i % 16 == 0 else "") + format(data_bytes[i],'02x') + ' '
            for i in range(0,datalen) 
        ]
    )
}

int testfunc(void) {{
\ttry {{
\t// test statement here
\t {'\n\t'.join(test_statement_list)}
\t}}
\tcatch (const exception &e) {{
\t\tcerr << "Exception: " << e.what() << endl;
\t\treturn EXIT_FAILURE;
\t}}
\tcerr << "PASS!" << endl;
\treturn EXIT_SUCCESS;
}}
'''

cpp_file_out.write(function_defination)
cpp_file_out.close()

#print(function_defination)